package com.irdstudio.efp.batch.service.impl.hjwp;

import com.irdstudio.basic.framework.core.base.FrameworkService;
import com.irdstudio.basic.framework.core.bean.TxtFileLoadBean;
import com.irdstudio.basic.framework.core.util.TimeUtil;
import com.irdstudio.basic.framework.core.util.TxtFileLoadPlugin;
import com.irdstudio.efp.batch.service.facade.hjwp.SynLoanRepayPlanProcessService;
import com.irdstudio.efp.console.service.facade.PubSysInfoService;
import com.irdstudio.efp.loan.service.facade.AccLoanService;
import com.irdstudio.efp.loan.service.facade.LoanRepayPlanService;
import com.irdstudio.efp.loan.service.facade.SyncRepayPlanDiffLogService;
import com.irdstudio.efp.loan.service.vo.AccLoanVO;
import com.irdstudio.efp.loan.service.vo.LoanRepayPlanVO;
import com.irdstudio.efp.loan.service.vo.SyncRepayPlanDiffLogVO;
import com.irdstudio.efp.nls.service.facade.NlsApplyInfoService;
import com.irdstudio.efp.nls.service.vo.NlsApplyInfoVO;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileNotFoundException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 晚批同步互金借据、还款计划、还款信息数据-还款计划同步
 * priemrxiao htd
 */
@Service("synLoanRepayPlanProcessService")
public class SynLoanRepayPlanProcessServiceImpl implements SynLoanRepayPlanProcessService, FrameworkService, SynFileDataInterface {
    /**
     * 日志
     */
    private static Logger logger = LoggerFactory.getLogger(SynLoanRepayPlanProcessServiceImpl.class);
    /**
     * 状态map
     */
    private static final HashMap<String, String> tempStatus = new HashMap<String, String>();
    static {
        //N	正常
        //O	逾期
        //P	结清
        //正常
        tempStatus.put("ZHC", "N");
        //逾期
        tempStatus.put("YUQ", "O");
        //结清
        tempStatus.put("PO", "P");
    }

    @Autowired
    @Qualifier("accLoanRepayPlanService")
    private LoanRepayPlanService loanRepayPlanService;

    @Autowired
    private PubSysInfoService pubSysInfoService;

    @Autowired
    private SyncRepayPlanDiffLogService syncRepayPlanDiffLogService;

    @Autowired
    private AccLoanService accLoanService;

    @Autowired
    private NlsApplyInfoService nlsApplyInfoService;

    /**
     * 营业日
     */
    private String openDay;

    /**
     * 批次开始执行时间
     */
    private Date batchRunDate;

    /**
     * 批次日期
     */
    private String batchSubDate;

    private ArrayList<SyncRepayPlanDiffLogVO> diffLogs = new ArrayList<>();


    @Override
    public Boolean synRepayPlan(String sub_date_date) throws Exception {
        logger.info("批次时间：[{}]，互金晚批同步还款计划开始运行。文件路径：[{}]；dat文件名：[{}]；ok文件名：[{}]", sub_date_date, sedLoanFilePath, fileNameOfDat, fileNamOfOk);
        batchSubDate = sub_date_date;
        batchRunDate = new Date();
        //查询当前的账务日期
        openDay = pubSysInfoService.getOpenday("1001");
        if (StringUtils.isEmpty(openDay)) {
            throw new Exception("获取openday为空");
        }
        logger.info("互金晚批同步还款计划当前营业时间为：[{}]",openDay);
        String fileUrl = sedLoanFilePath + getCurrentBatchFileName(fileNameOfDat, sub_date_date);
        //判断文件是否存在
        if (!new File(fileUrl).exists()) {
            logger.info("批次时间：[{}]，互金晚批同步还款计划路径[{}]的文件不存在",sub_date_date,fileUrl);
            throw new FileNotFoundException("还款计划数据不存在，文件路径：" + fileUrl);
        }
        logger.info("互金晚批同步-开始：【{}】", fileUrl);
        if (getOkFileDataNum(sedLoanFilePath, fileNamOfOk, sub_date_date) < 1) {
            logger.info("获取到的ok文件中的文件数据条数为空，所以不做处理");
            return Boolean.TRUE;
        }
        boolean flag = validateOkFile(getFileNum(fileUrl), sedLoanFilePath, fileNamOfOk, sub_date_date);
        if (!flag) {
            logger.info("互金晚批同步-ok文件数量校验不通过，文件：[{}]；ok文件：[{}]", fileNameOfDat, fileNamOfOk);
            return flag;
        }
        TxtFileLoadPlugin txtFileLoadPlugin = new TxtFileLoadPlugin(fileUrl, "\u0002", "UTF-8", 0, 1000);
        List<TxtFileLoadBean> repayPlanList = txtFileLoadPlugin.run(new SynRepayPlanVO());
        // 校验文件
        dueData(repayPlanList, sub_date_date);
        if (repayPlanList.size() != 0) {
            while (!repayPlanList.get(repayPlanList.size() - 1).isReadedComplete) {
                txtFileLoadPlugin.setFirstRead(false);
                repayPlanList = txtFileLoadPlugin.run(new SynRepayPlanVO());
                if (repayPlanList.size() == 0) {
                    break;
                }
                dueData(repayPlanList, sub_date_date);
            }
        }
        logger.error(fileUrl + "Ok文件验证失败!!!");
        return true;
    }


    /**
     * 同步还款计划处理逻辑: <br>
     * 0.1:caoxin:2019/6/12 11:47: TODO: <br>
     *
     * @return
     * @author caoxin
     * @date 2019/6/12 11:47
     * @version 0.1
     * @since 2019/6/12 11:47
     */
    private void dueData(List<TxtFileLoadBean> repayPlanList, String subDate) throws Exception {
        logger.info("批次时间：[{}]，互金晚批同步还款计划执行函数dueData",subDate);
        diffLogs.clear();
        if (repayPlanList == null) {
            return;
        }
        if (repayPlanList.isEmpty()) {
            return;
        }
        List<String> refNbrs = repayPlanList.stream().map(r -> ((SynRepayPlanVO)r).getRefNbr()).distinct().collect(Collectors.toList());
        //根据还款计划id 查询存在的还款计划信息
        List<LoanRepayPlanVO> loanRepayPlanS = loanRepayPlanService.queryRepayPlansByRefNbr(refNbrs);
        //插入的数据
        List<LoanRepayPlanVO> insertList = new ArrayList<>();
        for (TxtFileLoadBean txtFileLoadBean : repayPlanList) {
            // 互金文件对象
            SynRepayPlanVO synRepayPlanVO = (SynRepayPlanVO) txtFileLoadBean;
            // 获取对应的网贷记录
            LoanRepayPlanVO loanRepayPlanVO=getFromList(loanRepayPlanS,synRepayPlanVO.getRefNbr(),synRepayPlanVO.getTerm());
            if (loanRepayPlanVO == null) {
                //网贷记录为空 保存数据到差异表
                insertDiffLog("1",synRepayPlanVO,null,"网贷记录为空");
                continue;
            }
            if (!SyncUtil.checkDate(loanRepayPlanVO.getBizDate(), openDay)) {
                insertDiffLog("3", synRepayPlanVO, loanRepayPlanVO, "bizDate和openDate校验不通过");
                continue;
            } else if ("P".equals(loanRepayPlanVO.getStatus()) && (LocalDate.parse(loanRepayPlanVO.getBizDate(), DateTimeFormatter.ofPattern("yyyy-MM-dd")).until(LocalDate.parse(batchSubDate, DateTimeFormatter.ofPattern("yyyy-MM-dd")), ChronoUnit.DAYS) > 0)) {
                //如果结清状态并且bizday<文件日期 那么不做更新
                logger.info("还款计划信息因为在网贷已经是结清状态了，所以不做处理.借据号：[{}],期次：[{}].", loanRepayPlanVO.getRefNbr(), loanRepayPlanVO.getTerm());
                insertDiffLog("3", synRepayPlanVO, loanRepayPlanVO, "结清状态并且bizday小于文件日期");
                continue;
            } else {
                insertDiffLog("2", synRepayPlanVO, loanRepayPlanVO, "正常更新");
            }
            // 对象赋值
            beanCopy(synRepayPlanVO, loanRepayPlanVO);
            // 业务日期
            setBizDate(subDate, loanRepayPlanVO);
            //loanRepayPlanVO.setBizDate(subDate);
            // 期数
            loanRepayPlanVO.setTerm(synRepayPlanVO.getTerm());
            // 状态
            loanRepayPlanVO.setStatus(tempStatus.get(synRepayPlanVO.getStatus()));
            // 已还本金
            loanRepayPlanVO.setPrincipalPaid(Optional.ofNullable(synRepayPlanVO.getPrincipal()).orElse(BigDecimal.ZERO).subtract(Optional.ofNullable(synRepayPlanVO.getNotPrincipalPaid()).orElse(BigDecimal.ZERO)));
            // 已还利息
            loanRepayPlanVO.setInterestPaid(Optional.ofNullable(synRepayPlanVO.getInterest()).orElse(BigDecimal.ZERO).subtract(Optional.ofNullable(synRepayPlanVO.getNotInterestPaid()).orElse(BigDecimal.ZERO)));
            // 已还罚息
            loanRepayPlanVO.setPenaltyPaid(Optional.ofNullable(synRepayPlanVO.getPenaltyDue()).orElse(BigDecimal.ZERO).subtract(Optional.ofNullable(synRepayPlanVO.getNotPenaltyPaid()).orElse(BigDecimal.ZERO)));
            // 已还复利
            loanRepayPlanVO.setComIntPaid(Optional.ofNullable(synRepayPlanVO.getComIntDue()).orElse(BigDecimal.ZERO).subtract(Optional.ofNullable(synRepayPlanVO.getNotComIntPaid()).orElse(BigDecimal.ZERO)));
            // 应还费用 应还本金 +应还利息 +应还罚息 +应还复利
            loanRepayPlanVO.setFeeDue(getFeeDue(loanRepayPlanVO));
            // 已还费用 已还本金 +已还利息 +已还罚息 +已还复利
            loanRepayPlanVO.setFeePaid(getFeePaid(loanRepayPlanVO));

            //宽限期到期日 到期日期+0（普税贷不支持宽限期）
            loanRepayPlanVO.setGraceDate(synRepayPlanVO.getStmtDate().trim());
            if (StringUtils.isNotEmpty(loanRepayPlanVO.getGraceDate())) {
                //loanRepayPlanVO.setGraceDate(synRepayPlanVO.getStmtDate().trim());
                loanRepayPlanVO.setGraceDate(synRepayPlanVO.getGraceDate().trim());
            }
            //是否逾期过字段赋值
            if ("O".equals(loanRepayPlanVO.getStatus())) {
                loanRepayPlanVO.setIsOverDue("1");
            }
            //还款总期数赋值为0 等借据信息同步完成则进行进行修正
            //loanRepayPlanVO.setInitTerm(0);
            insertList.add(loanRepayPlanVO);
         }
        if (insertList.size() > 0) {
            int num = loanRepayPlanService.insertOrUpdatePsd(insertList);
            logger.info("批次时间：[{}]，互金晚批同步还款计划执行函数dueData插入或者更新还款计划信息变更的条数为：[{}]", subDate, num);
        }
        if (diffLogs.size() > 0) {
            int num = syncRepayPlanDiffLogService.batchInsert(diffLogs);
            logger.info("批次时间：[{}]，互金晚批同步还款计划执行函数dueData插入差异表的条数为：[{}]", subDate, num);

        }
        logger.info("批次时间：[{}]，互金晚批同步还款计划执行函数dueData结束",subDate);
    }

    private void setBizDate(String subDate, LoanRepayPlanVO loanRepayPlanVO) throws Exception {
        //查询借据信息
        AccLoanVO param = new AccLoanVO();
        param.setBillNo(loanRepayPlanVO.getRefNbr());
        AccLoanVO accLoanVO = accLoanService.queryByPk(param);
        if (accLoanVO != null) {
            //如果放款时间大于文件日期则使用放款时间
            String firstDisbDate = accLoanVO.getFirstDisbDate();
            int i = TimeUtil.compareDates(accLoanVO.getFirstDisbDate(), batchSubDate);
            if (i == 1) {
                loanRepayPlanVO.setBizDate(firstDisbDate);
                return;
            }
        }
        loanRepayPlanVO.setBizDate(subDate);
    }

    /**
     * 添加数据到差异表
     *
     * @param diffType
     * @param synRepayPlanVO
     */
    private void insertDiffLog(String diffType, SynRepayPlanVO synRepayPlanVO, LoanRepayPlanVO loanRepayPlanVO, String msg) {
        SyncRepayPlanDiffLogVO syncRepayPlanDiffLogVO = new SyncRepayPlanDiffLogVO();
        syncRepayPlanDiffLogVO.setId(UUID.randomUUID().toString());
        syncRepayPlanDiffLogVO.setDataType(diffType);
        syncRepayPlanDiffLogVO.setCreateTime(new Date());
        syncRepayPlanDiffLogVO.setBatchRunTime(batchRunDate);
        syncRepayPlanDiffLogVO.setOpenDay(openDay);
        syncRepayPlanDiffLogVO.setBatchDay(batchSubDate);
        syncRepayPlanDiffLogVO.setHjRefNbr(synRepayPlanVO.getRefNbr());
        syncRepayPlanDiffLogVO.setHjTerm(synRepayPlanVO.getTerm());
        syncRepayPlanDiffLogVO.setHjBeginDate(synRepayPlanVO.getBeginDate());
        syncRepayPlanDiffLogVO.setHjStmtDate(synRepayPlanVO.getStmtDate());
        syncRepayPlanDiffLogVO.setHjStatus(synRepayPlanVO.getStatus());
        syncRepayPlanDiffLogVO.setHjPerAmt(synRepayPlanVO.getPerAmt());
        syncRepayPlanDiffLogVO.setHjPrincipal(synRepayPlanVO.getPrincipal());
        syncRepayPlanDiffLogVO.setHjInterest(synRepayPlanVO.getInterest());
        syncRepayPlanDiffLogVO.setHjPenaltyDue(synRepayPlanVO.getPenaltyDue());
        syncRepayPlanDiffLogVO.setHjComIntDue(synRepayPlanVO.getComIntDue());
        syncRepayPlanDiffLogVO.setHjNotPrincipalPaid(synRepayPlanVO.getNotPrincipalPaid());
        syncRepayPlanDiffLogVO.setHjNotInterestPaid(synRepayPlanVO.getNotInterestPaid());
        syncRepayPlanDiffLogVO.setHjNotPenaltyPaid(synRepayPlanVO.getNotPenaltyPaid());
        syncRepayPlanDiffLogVO.setHjNotComIntPaid(synRepayPlanVO.getNotComIntPaid());
        syncRepayPlanDiffLogVO.setHjClearDate(synRepayPlanVO.getClearDate());
        if (Objects.isNull(loanRepayPlanVO)) {
            diffLogs.add(syncRepayPlanDiffLogVO);
            return;
        }
        syncRepayPlanDiffLogVO.setWdRefNbr(loanRepayPlanVO.getRefNbr());
        syncRepayPlanDiffLogVO.setWdTerm(loanRepayPlanVO.getTerm());
        syncRepayPlanDiffLogVO.setWdBeginDate(loanRepayPlanVO.getBeginDate());
        syncRepayPlanDiffLogVO.setWdStmtDate(loanRepayPlanVO.getStmtDate());
        syncRepayPlanDiffLogVO.setWdIsOverDue(loanRepayPlanVO.getIsOverDue());
        syncRepayPlanDiffLogVO.setWdStatus(loanRepayPlanVO.getStatus());
        syncRepayPlanDiffLogVO.setWdPerAmt(loanRepayPlanVO.getPerAmt());
        syncRepayPlanDiffLogVO.setWdPrincipal(loanRepayPlanVO.getPrincipal());
        syncRepayPlanDiffLogVO.setWdInterest(loanRepayPlanVO.getInterest());
        syncRepayPlanDiffLogVO.setWdPenaltyDue(loanRepayPlanVO.getPenaltyDue());
        syncRepayPlanDiffLogVO.setWdComIntDue(loanRepayPlanVO.getComIntDue());
        syncRepayPlanDiffLogVO.setWdClearDate(loanRepayPlanVO.getClearDate());
        syncRepayPlanDiffLogVO.setWdGraceDate(loanRepayPlanVO.getGraceDate());
        syncRepayPlanDiffLogVO.setWdProductCd(loanRepayPlanVO.getProductCd());
        syncRepayPlanDiffLogVO.setWdPrincipalPaid(loanRepayPlanVO.getPrincipalPaid());
        syncRepayPlanDiffLogVO.setWdInterestPaid(loanRepayPlanVO.getInterestPaid());
        syncRepayPlanDiffLogVO.setWdPenaltyPaid(loanRepayPlanVO.getPenaltyPaid());
        syncRepayPlanDiffLogVO.setWdComIntPaid(loanRepayPlanVO.getComIntPaid());
        syncRepayPlanDiffLogVO.setWdFeeDue(loanRepayPlanVO.getFeeDue());
        syncRepayPlanDiffLogVO.setWdFeePaid(loanRepayPlanVO.getFeePaid());
        syncRepayPlanDiffLogVO.setWdInitTerm(loanRepayPlanVO.getInitTerm());
        syncRepayPlanDiffLogVO.setWdBizDate(loanRepayPlanVO.getBizDate());
        //差异信息
        syncRepayPlanDiffLogVO.setWdBkCol6(msg);
        diffLogs.add(syncRepayPlanDiffLogVO);
        return;

    }

    private BigDecimal getFeeDue(LoanRepayPlanVO loanRepayPlanVO) {
        BigDecimal feeDue = BigDecimal.ZERO;
        if (!Objects.isNull(loanRepayPlanVO.getPrincipal())) {
            feeDue = feeDue.add(loanRepayPlanVO.getPrincipal());
        }
        if (!Objects.isNull(loanRepayPlanVO.getInterest())) {
            feeDue = feeDue.add(loanRepayPlanVO.getInterest());
        }
        if (!Objects.isNull(loanRepayPlanVO.getPenaltyDue())) {
            feeDue = feeDue.add(loanRepayPlanVO.getPenaltyDue());
        }
        if (!Objects.isNull(loanRepayPlanVO.getComIntDue())) {
            feeDue = feeDue.add(loanRepayPlanVO.getComIntDue());
        }
        return feeDue;
    }
    private BigDecimal getFeePaid(LoanRepayPlanVO loanRepayPlanVO) {
        BigDecimal feePaid = BigDecimal.ZERO;
        if (!Objects.isNull(loanRepayPlanVO.getPrincipalPaid())) {
            feePaid = feePaid.add(loanRepayPlanVO.getPrincipalPaid());
        }
        if (!Objects.isNull(loanRepayPlanVO.getInterestPaid())) {
            feePaid = feePaid.add(loanRepayPlanVO.getInterestPaid());
        }
        if (!Objects.isNull(loanRepayPlanVO.getPenaltyPaid())) {
            feePaid = feePaid.add(loanRepayPlanVO.getPenaltyPaid());
        }
        if (!Objects.isNull(loanRepayPlanVO.getComIntPaid())) {
            feePaid = feePaid.add(loanRepayPlanVO.getComIntPaid());
        }
        return feePaid;
    }


    /**
     * 根据借据号和还款计划期数查询在列表中的记录
     * @param sourceList
     * @param refNbr
     * @param term
     * @return
     */
    private LoanRepayPlanVO getFromList(List<LoanRepayPlanVO> sourceList, String refNbr, int term) {
        if (sourceList==null) {
            return null;
        }
        if (sourceList.isEmpty()) {
            return null;
        }
        for (LoanRepayPlanVO loanRepayPlanVO : sourceList) {
            if (loanRepayPlanVO.getRefNbr().equals(refNbr) && loanRepayPlanVO.getTerm()==term) {
                return loanRepayPlanVO;
            }
        }
        return null;
    }


    private String sedLoanFilePath="/home/ocmuser/share/infile/psd/syncfile/";

    private String fileNameOfDat="idl_dm_repay_plan_info_i.$date$.dat";

    private String fileNamOfOk="idl_dm_repay_plan_info_i.$date$.ok";
}
